package com.huamoxi.filter;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.huamoxi.consts.RedisConst;
import com.huamoxi.consts.ResponseConst;
import com.huamoxi.consts.SecurityConst;
import com.huamoxi.utils.CacheUtil;
import com.huamoxi.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private CacheUtil cacheUtil;

    @Value("${jwt.cacheExp}")
    private Long cacheExp;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String header = request.getHeader("Authorization");

        if (header == null || !header.startsWith("Bearer ")) {
            // 未携带正确格式的token 返回错误信息
            backErrMsg(response, "请先登录");
        } else {
            // 如果携带了正确格式的token要先得到token
            String token = header.replace("Bearer ", "");

            // 校验
            try {
                Claims claims = jwtUtil.verifyToken(token);

                if ("1".equals(claims.get("status").toString())) {
                    backErrMsg(response, "账号已被锁定");
                }

                if (claims.get("id") != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    // 登录信息 存入redis
                    cacheUtil.set(RedisConst.TOKEN_CACHE_KEY_PREFIX + claims.get("id"), token, cacheExp);

                    // 获取角色
                    String jsonStr = cacheUtil.get(RedisConst.USER_CACHE_AUTHORITIES + claims.get("id"));

                    List<GrantedAuthority> authorities = JSON.parseArray(jsonStr, GrantedAuthority.class);

                    UsernamePasswordAuthenticationToken authResult = new UsernamePasswordAuthenticationToken(
                            claims.get(SecurityConst.NAME),
                            null,
                            authorities
                    );
                    SecurityContextHolder.getContext().setAuthentication(authResult);
                }
                chain.doFilter(request, response);
            } catch (Exception e) {
                if (e instanceof JwtException) {
                    backErrMsg(response, ResponseConst.ERR_LOGIN_EXP_TOKEN);
                } else {
                    backErrMsg(response, "请先登录");
                }
            }
        }
    }

    private void backErrMsg(HttpServletResponse response, String msg) throws IOException {
        // 如果携带错误的token，则给用户提示请登录！
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        PrintWriter out = null;
        try {
            out = response.getWriter();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", HttpServletResponse.SC_FORBIDDEN);
        resultMap.put("msg", msg);
        out.write(JSONObject.toJSONString(resultMap));
        out.flush();
        out.close();
    }
}
